package com.dingreading.cloud.soms.service.impl;

import com.dingreading.cloud.common.util.DateUtil;
import com.dingreading.cloud.common.util.NepUtil;
import com.dingreading.cloud.common.util.PageUtil;
import com.dingreading.cloud.soms.dto.CaCallNamesDto;
import com.dingreading.cloud.soms.dto.CallNameHourDto;
import com.dingreading.cloud.soms.entity.CaCallNames;
import com.dingreading.cloud.soms.entity.table.CaCallNamesTableDef;
import com.dingreading.cloud.soms.mapper.CaCallNamesMapper;
import com.dingreading.cloud.soms.service.CaCallNamesService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.core.update.UpdateWrapper;
import com.mybatisflex.core.util.UpdateEntity;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.dingreading.cloud.soms.entity.table.MembersTableDef.members;


/**
 * 服务层实现。
 *
 * @author Administrator
 * @since 2023-11-22
 */
@Service
public class CaCallNamesServiceImpl extends BaseServiceImpl<CaCallNamesMapper, CaCallNames, CaCallNamesTableDef> implements CaCallNamesService {

    @Override
    protected CaCallNamesTableDef getTable() {
        return CaCallNamesTableDef.caCallNames;
    }

    @Override
    public Page<CaCallNamesDto> pageList(
            PageUtil pageUtil, String storeUid, String keyword, Integer callStatus, String beginDate, String endDate,
            String teacherUid, String projectUid, Integer status, int staffRole, String username
    ) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));
        if (StringUtils.isNotBlank(keyword))
            condition.and(table.className.like(keyword)
                                  .or(table.roomName.like(keyword))
                                  .or(table.mob.like(keyword))
                                  .or(table.teacherName.like(keyword))
                                  .or(table.productName.like(keyword))
                                  .or(members.memberName.like(keyword))
            );
        if (null != callStatus)
            condition.and(table.callStatus.eq(callStatus));
        if (StringUtils.isNotBlank(projectUid))
            condition.and(table.projectUid.eq(projectUid));
        if (null != status)
            condition.and(table.status.eq(status));
        if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate))
            condition.and(table.teachDate.between(beginDate, endDate));

        if (staffRole == 6) {
            // 员工是导读，只能看自己的记录
            if (StringUtils.isNotBlank(username))
                condition.and(table.teacherUid.eq(username));
        } else {
            if (StringUtils.isNotBlank(teacherUid))
                condition.and(table.usernames.like("," + teacherUid + ","));
        }

        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.allColumns, members.memberName.as("newMemberName"))
                .from(table)
                .leftJoin(members).on(table.memberUid.eq(members.uid))
                .where(condition)
                .orderBy(table.id.desc());

        return getMapper().paginateWithRelationsAs(Page.of(pageUtil.getPage(), pageUtil.getRows()), wrapper, CaCallNamesDto.class);
    }

    @Override
    public int dropBean(String storeUid, String lessonUid, Long id) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.lessonUid.eq(lessonUid))
                .and(table.status.in(-1, 0, 1));
        if (null != id)
            condition.and(table.id.eq(id));

        return getMapper().deleteByCondition(condition);

    }

    @Override
    public String getTempMembers(String storeUid, String lessonUid, String memberUid) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.lessonUid.eq(lessonUid))
                .and(table.memberUid.eq(memberUid));

        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.studentTypeName)
                .from(table)
                .where(condition);

        return getMapper().selectObjectByQueryAs(wrapper, String.class);
    }

    @Override
    public List<CaCallNames> listByStoreUidAndLessonUid(String storeUid, String lessonUid) {
        QueryCondition condition = table.lessonUid.eq(lessonUid);
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.studentType.asc());

        return getMapper().selectListByQuery(wrapper);

    }

    @Override
    public List<CaCallNamesDto> getLessonCallNameDtos(String storeUid, String lessonUid) {
        QueryCondition condition = table.lessonUid.eq(lessonUid);
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.studentType.asc());

        return getMapper().selectListWithRelationsByQueryAs(wrapper, CaCallNamesDto.class);
    }

    @Override
    public CaCallNames getTempCallName(String storeUid, String lessonUid, String memberUid) {
        QueryCondition condition = table.lessonUid.eq(lessonUid)
                .and(table.storeUid.eq(storeUid))
                .and(table.memberUid.eq(memberUid))
                .and(table.studentType.ne(1));

        return getMapper().selectOneByCondition(condition);
    }

    @Override
    public List<CaCallNamesDto> getNotReachAndAskLeaveMember(String storeUid, String scheduleUid, String lessonUid) {
        QueryCondition condition = table.lessonUid.eq(lessonUid)
                .and(table.storeUid.eq(storeUid))
                .and(table.scheduleUid.eq(scheduleUid))
                .and(table.callStatus.in(3, 4))
                .and(table.status.eq(2));

        QueryWrapper wrapper = QueryWrapper.create().where(condition);

        return getMapper().selectListByQueryAs(wrapper, CaCallNamesDto.class);
    }

    @Override
    public long getTempMemberNum(String storeUid, String lessonUid) {
        QueryCondition condition = table.lessonUid.eq(lessonUid)
                .and(table.storeUid.eq(storeUid))
                .and(table.studentType.in(2, 3, 4));

        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.id)
                .from(table)
                .where(condition);

        return getMapper().selectCountByQuery(wrapper);

    }

    @Override
    public long getMemberMonthAuditionCnt(String storeUid, String memberUid) {
        Date minDate = DateUtil.getMonthMinDate();
        Date maxDate = DateUtil.getMonthMaxDate();
        String min = DateUtil.getDefaultTime2DateStr(minDate);
        String max = DateUtil.getDefaultTime2DateStr(maxDate);

        QueryCondition condition = table.memberUid.eq(memberUid)
                .and(table.storeUid.eq(storeUid))
                .and(table.studentType.eq(4))
                .and(table.teachDate.between(min, max));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition);

        return getMapper().selectCountByQuery(wrapper);
    }

    @Override
    public boolean setCallOk(
            String corpUid, String storeUid, String lessonUid, Long id,
            String orderCode, String serviceUid, String orderType, Integer isGift, Double unitAmount,
            int hourType, String hourTypeName, String staffUid, String staffName, Date closeTime
    ) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.corpUid.eq(corpUid))
                .and(table.lessonUid.eq(lessonUid))
                .and(table.id.eq(id))
                .and(table.status.eq(1));

        return UpdateChain.of(CaCallNames.class)
                .set(table.orderCode, orderCode)
                .set(table.serviceUid, serviceUid)
                .set(table.orderType, orderType)
                .set(table.isGift, isGift)
                .set(table.unitAmount, unitAmount)
                .set(table.hourType, hourType)
                .set(table.hourTypeName, hourTypeName)
                .set(table.status, 2)
                .set(table.closeStaffUid, NepUtil.nullToZero(staffUid))
                .set(table.closeStaffName, NepUtil.nullToZero(staffName))
                .set(table.closeTime, closeTime)
                .where(condition)
                .update();
    }

    @Override
    public void setOkAnNoHour(String corpUid, String storeUid, String lessonUid, List<Long> ids, String staffUid, String staffName, Date closeTime) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.corpUid.eq(corpUid))
                .and(table.lessonUid.eq(lessonUid))
                .and(table.id.in(ids))
                .and(table.callStatus.isNotNull())
                .and(table.status.eq(1));

        CaCallNames data = UpdateEntity.of(CaCallNames.class);
        UpdateWrapper<CaCallNames> wrapper = UpdateWrapper.of(data);
        wrapper.set(table.hourType, -1)
                .set(table.hourTypeName, "未扣")
                .set(table.status, 2)
                .set(table.closeStaffUid, NepUtil.nullToZero(staffUid))
                .set(table.closeStaffName, NepUtil.nullToZero(staffName))
                .set(table.closeTime, closeTime);

        getMapper().updateByCondition(data, condition);
    }

    @Override
    public boolean updateMemberMakeUp(String storeUid, String makeupLessonUid, String lessonUid, String memberUid) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.lessonUid.eq(makeupLessonUid))
                .and(table.memberUid.eq(memberUid))
                .and(table.callStatus.in(3, 4))
                .and(table.status.eq(2))
                .and(table.makeupStatus.eq(0));

        return UpdateChain.of(CaCallNames.class)
                .set(table.makeupStatus, 1)
                .set(table.makeupLessonUid, lessonUid)
                .where(condition)
                .update();
    }

    @Override
    public boolean dropMemberMakeUp(String storeUid, String lessonUid, String memberUid) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.memberUid.eq(memberUid))
                .and(table.callStatus.in(3, 4))
                .and(table.status.eq(2))
                .and(table.makeupLessonUid.eq(lessonUid))
                .and(table.makeupStatus.eq(1));

        return UpdateChain.of(CaCallNames.class)
                .set(table.makeupStatus, 0)
                .set(table.makeupLessonUid, null)
                .where(condition)
                .update();

    }

    @Override
    public void setCancel(String corpUid, String lessonUid, String staffUid, String staffName) {
        QueryCondition condition = table.corpUid.eq(corpUid)
                .and(table.lessonUid.eq(lessonUid))
                .and(table.status.eq(0))
                .and(table.callTime.isNull());

        UpdateChain.of(CaCallNames.class)
                .set(table.status, -1)
                .set(table.lastStaffUid, NepUtil.nullToZero(staffUid))
                .set(table.lastStaffName, NepUtil.nullToZero(staffName))
                .where(condition)
                .update();
    }

    @Override
    public void dropClassCallName(String storeUid, Long classId, String memberUid) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.classId.eq(classId))
                .and(table.memberUid.eq(memberUid))
                .and(table.closeTime.isNull())
                .and(table.studentType.eq(1))
                .and(table.status.in(0, 1));

        getMapper().deleteByCondition(condition);

    }

    @Override
    public List<CaCallNames> getMemberCallListV3(
            String corpUid, String storeUid, String keyword, Integer callStatus, String beginDate, String endDate,
            String username, String projectUid, Integer status, List<Integer> callStatusList, List<Integer> hourTypeList
    ) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(corpUid))
            condition.and(table.corpUid.eq(corpUid));
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));
        if (StringUtils.isNotBlank(keyword))
            condition.and(table.className.like(keyword)
                                  .or(table.roomName.like(keyword))
                                  .or(table.memberName.like(keyword))
                                  .or(table.mob.like(keyword))
                                  .or(table.productName.like(keyword))
                                  .or(table.teacherName.like(keyword))
            );
        if (null != callStatus)
            condition.and(table.callStatus.eq(callStatus));
        if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate))
            condition.and(table.teachDate.between(beginDate, endDate));
        if (StringUtils.isNotBlank(projectUid))
            condition.and(table.projectUid.eq(projectUid));
        if (StringUtils.isNotBlank(username))
            condition.and(table.usernames.like("," + username + ","));
        if (null != status)
            condition.and(table.status.eq(status));
        if (CollectionUtils.isNotEmpty(callStatusList))
            condition.and(table.callStatus.in(callStatusList));
        if (CollectionUtils.isNotEmpty(hourTypeList))
            condition.and(table.hourType.in(hourTypeList));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.memberUid.asc(), table.teachDate.desc());

        return getMapper().selectListByQuery(wrapper);
    }

    @Override
    public Map<String, Long> getCntByServiceUids(List<String> uids) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.serviceUid.in(uids));

        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.serviceUid, QueryMethods.count(table.id).as("cnt"))
                .where(condition)
                .groupBy(table.serviceUid);

        List<Row> rows = getMapper().selectRowsByQuery(wrapper);

        Map<String, Long> map = new HashMap<>();
        if (CollectionUtils.isNotEmpty(rows)) {
            for (Row row : rows) {
                String serviceUid = row.getString("service_uid");
                Long cnt = row.getLong("cnt");
                map.put(serviceUid, cnt);
            }
        }

        return map;
    }

    @Override
    public boolean setFreeOk(String corpUid, String storeUid, String lessonUid, String staffUid, String staffName, Date closeTime) {
        QueryCondition condition = table.corpUid.eq(corpUid)
                .and(table.storeUid.eq(storeUid))
                .and(table.lessonUid.eq(lessonUid))
                .and(table.status.eq(1));

        return UpdateChain.of(CaCallNames.class)
                .set(table.hourType, 0)
                .set(table.hourTypeName, "免费")
                .set(table.status, 2)
                .set(table.closeStaffUid, NepUtil.nullToZero(staffUid))
                .set(table.closeStaffName, NepUtil.nullToZero(staffName))
                .set(table.closeTime, closeTime)
                .where(condition)
                .update();
    }

    @Override
    public List<CaCallNamesDto> listByLessonUidIn(List<String> lessonUids) {
        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.allColumns, members.memberName.as("newMemberName"))
                .from(table)
                .leftJoin(members).on(table.memberUid.eq(members.uid))
                .where(CaCallNames::getLessonUid).in(lessonUids);
        return getMapper().selectListByQueryAs(wrapper, CaCallNamesDto.class);
    }

    @Override
    public List<CaCallNamesDto> getByServiceUidV2(String serviceUid) {
        QueryWrapper wrapper = QueryWrapper.create()
                .where(CaCallNames::getServiceUid).eq(serviceUid)
                .orderBy(CaCallNames::getId).desc();
        return getMapper().selectListByQueryAs(wrapper, CaCallNamesDto.class);
    }

    @Override
    public void dropByScheduleUid(String storeUid, String scheduleUid) {
        QueryWrapper wrapper = QueryWrapper.create()
                .where(CaCallNames::getStoreUid).eq(storeUid)
                .and(CaCallNames::getStatus).in(-1, 0);
        if (StringUtils.isNotBlank(scheduleUid))
            wrapper.and(CaCallNames::getScheduleUid).eq(scheduleUid);
        getMapper().deleteByQuery(wrapper);
    }

    @Override
    public void updateUnitAmount(String uid, double unitAmount) {
        UpdateChain.of(CaCallNames.class)
                .set(table.unitAmount, unitAmount)
                .where(table.serviceUid.eq(uid))
                .update();
    }

    @Override
    public Map<String, Map<String, Long>> hourList(List<String> lessonUidList) {
        QueryWrapper wrapper = QueryWrapper.create()
                .where(table.lessonUid.in(lessonUidList));
        List<CallNameHourDto> list = getMapper().selectListByQueryAs(wrapper, CallNameHourDto.class);

        Map<String, Map<String, Long>> lessonHourMap = null;
        if (CollectionUtils.isNotEmpty(list)) {
            lessonHourMap = list.stream()
                    .collect(Collectors.groupingBy(CallNameHourDto::getLessonUid,
                                                   Collectors.groupingBy(CallNameHourDto::getHourTypeName, Collectors.counting())));
        }

        return lessonHourMap;
    }

    @Override
    public CaCallNames getByCallNamesUid(String corpUid, String storeUid, String callNamesUid) {
        QueryCondition condition = QueryCondition.createEmpty()
                .and(table.corpUid.eq(corpUid))
                .and(table.storeUid.eq(storeUid))
                .and(table.uid.eq(callNamesUid));
        return getMapper().selectOneByCondition(condition);
    }

}
